package a06_BlockQueue;

/**
 * @Author quan
 * @Description 自己实现阻塞队列
 * @Date 2023/5/7 15:23
 */
public class a02_MyBlockQueue {
    //之前队列底层实现用到的是链表和循环数组。现在阻塞队列就是在其基础上增加了阻塞等待的操作。
    //此处以数组实现为例：定义初始化变量
    //定义一个保存元素的数组
    private volatile int[] elementData = new int[3];
    //定义头部索引
    private volatile int head;
    //定义尾部索引
    private volatile int tail;
    //定义有效元素的个数
    private volatile int size;
    /**
     * 插入一个元素
     * @param val
     */
    public void put(int val) throws InterruptedException {
        //------在普通队列基础上加入等待和唤醒的操作，这两个操作与synchronized息息相关。
        //------一般new出来的对象，锁对象都是this（指大部分情况）
        synchronized(this){
            //1、判断元素是否已满:满了就阻塞等待
            while (size >= elementData.length){
                this.wait();
            }
            //2、队尾插入元素
            elementData[tail] = val;
            //3、更新tail索引:循环队列（之前队列的实现用得是取模运算，不是简单的++）
            tail++;
            if(tail >= elementData.length){
                tail=0;
            }
            //4、更新元素个数
            size++;
            //5、唤醒
            notifyAll();
        }
    }

    /**
     * 取出元素
     * @return
     */
    public int take() throws InterruptedException {
        //根据共享范围加锁，锁对象是this即可
        synchronized (this) {
            //1、判断队列是否为空:为空就阻塞
            while (size <= 0) {
                this.wait();
            }
            //2、从队首出队
            int val = elementData[head];
            //3、更新head下标
            head++;
            if (head >= elementData.length) {
                head = 0;
            }
            //4、修改有效元素的个数
            size--;
            //5、唤醒
            notifyAll();
            //6、返回队首元素
            return val;
        }
    }

}

